package com.rp.data.tcp_ws.server_tcp.echo;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.*;
import java.util.Calendar;

public class GA26875Decoder {

    private static final Logger log = LogManager.getLogger(GA26875Decoder.class);


    public static byte checkSum(byte[] bytes) {
        return checkSum(bytes, 0);
    }

    public static byte checkSum(byte[] bytes, int offset) {
        return checkSum(bytes, offset, bytes.length - offset);
    }

    public static byte checkSum(byte[] bytes, int offset, int len) {
        byte sum = 0;
        for (int i = offset; i < len + offset; i++) {
            sum += bytes[i];
        }
        return sum;
    }


    private static int readAddress(DataInput dataInput) throws IOException {
        int address = 0;
        for (int i = 0; i < 6; i++) {
            int b = dataInput.readUnsignedByte();
            if (b != 0) {
                address += ((b & 0xFF) << i * 8);
            }
        }
        return address;
    }

    public static boolean checkSum(byte[] bytes, byte predict) {
        return checkSum(bytes) == predict;
    }


    private static String uploadDeviceStatus(DataInput dataInput) throws IOException {

        StringBuilder builder = new StringBuilder();
        int objCount = dataInput.readUnsignedByte();//信息对象数目
        for (int i = 0; i < objCount; i++) {
            int sysType = dataInput.readUnsignedByte();//系统类型
            int sysAddr = dataInput.readUnsignedByte();//系统地址
            int componentType = dataInput.readUnsignedByte();//部件类型
            int placeNo = (dataInput.readUnsignedByte()) + ((dataInput.readByte() & 0xFF) << 8);//部件地址：位号
            int areaNo = (dataInput.readUnsignedByte()) + ((dataInput.readByte() & 0xFF) << 8);//部件地址：区号


            int compomentStatusL = dataInput.readByte();
            int compomentStatusH = dataInput.readByte();

            String status = "";

            switch (compomentStatusL) {
                case 0x80:
                    status = "延时";
                    break;

                case 0x40:
                    status = "反馈";
                    break;

                case 0x20:
                    status = "启动";
                    break;

                case 0x10:
                    status = "监管";
                    break;

                case 0x08:
                    status = "屏蔽";
                    break;

                case 0x04:
                    status = "故障";
                    break;

                case 0x02:
                    status = "火警";
                    break;

                case 0x01:
                    status = "测试运行";
                    break;

                case 0x00:
                    status = "正常运行";
                    break;
            }

            String componentName = "";
            switch (componentType) {
                case 40:
                    componentName = "感烟火灾探测器";
                    break;
                case 87:
                    componentName = "输入／输出模块";
                    break;

            }

            byte[] describe = new byte[31];
            dataInput.readFully(describe);

            String date = readDate(dataInput);

            builder.append(areaNo + "区" + placeNo + "号" + " " + componentName + " " + status + " " + date);
        }
        return builder.toString();

    }

    private static String readDate(DataInput dataInput) throws IOException {
        int second = dataInput.readUnsignedByte();
        int minute = dataInput.readUnsignedByte();
        int hour = dataInput.readUnsignedByte();
        int day = dataInput.readUnsignedByte();
        int month = dataInput.readUnsignedByte();
        int year = dataInput.readUnsignedByte() + 2000;
        return String.format("%d-%d-%d %d:%d:%d", year, month, day, hour, minute, second);
    }

    public static String dealData(byte[] data) throws IOException {
//        log.info("data:" + ByteUtils.bytesToHex(data));

        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        DataInput dataInput = new DataInputStream(bais);

        int typeTag = dataInput.readUnsignedByte();//类型标志
        switch (typeTag) {

            case 2://上传建筑消防设施部件运行状态
                return uploadDeviceStatus(dataInput);

            case 21://上传用户信息传输装置运行状态
                log.info("上传用户信息传输装置运行状态");
                break;

            case 136://上传用户信息传输装置运行状态恢复
                log.info("上传用户信息传输装置运行状态恢复");
                break;
            default:

                log.info("不支持");
        }

        return "";
    }


    public static byte[] decode(byte[] bytes) throws IOException {
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        DataInput dataInput = new DataInputStream(bais);

        int start1 = dataInput.readUnsignedByte();
        int start2 = dataInput.readUnsignedByte();
        int serialNum = dataInput.readUnsignedShort();
        int mainVersion = dataInput.readUnsignedByte();
        int minorVersion = dataInput.readUnsignedByte();

        String date = readDate(dataInput);

        int sourceAddress = readAddress(dataInput);
        int destinationAddress = readAddress(dataInput);

        int dataLength = (dataInput.readUnsignedByte()) + ((dataInput.readByte() & 0xFF) << 8);
        int cmd = dataInput.readUnsignedByte();

        String info = "";
        if (dataLength > 0) {
            //读取应用程序数据
            byte[] data = new byte[dataLength];
            dataInput.readFully(data);
            info = dealData(data);
        }

        if (checkSum(bytes, 2, bytes.length - 5) == bytes[bytes.length - 3]) {
            log.info("时间:" + date + "，用户编码:" + sourceAddress + "，城市代码：" + destinationAddress + ",数据长度:" + dataLength + "，命令:" + cmd + ", info:" + info);
        } else {
            log.error("校验失败");
        }

        Calendar calendar = Calendar.getInstance();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutput dataOutput = new DataOutputStream(baos);

        dataOutput.writeByte(start1);
        dataOutput.writeByte(start2);
        dataOutput.writeShort(serialNum);
        dataOutput.writeByte(mainVersion);
        dataOutput.writeByte(minorVersion);

        dataOutput.writeByte(calendar.get(Calendar.SECOND));
        dataOutput.writeByte(calendar.get(Calendar.MINUTE));
        dataOutput.writeByte(calendar.get(Calendar.HOUR_OF_DAY));
        dataOutput.writeByte(calendar.get(Calendar.DAY_OF_MONTH));
        dataOutput.writeByte(calendar.get(Calendar.MONTH) + 1);
        dataOutput.writeByte(calendar.get(Calendar.YEAR) - 2000);

//        dataOutput.write(bytes, 12, 12);

        dataOutput.write(bytes, 18, 6);
        dataOutput.write(bytes, 12, 6);


        dataOutput.writeShort(0);
        switch (cmd) {
            case 0x00://预留
            case 0x01://控制命令
                return null;

            case 0x02://发送数据
                dataOutput.writeByte(0x03);//确认


                break;

            case 0x04://请求
                dataOutput.writeByte(0x05);//应答
        }

        dataOutput.writeByte(checkSum(baos.toByteArray(), 2));
        dataOutput.writeByte(0x23);
        dataOutput.writeByte(0x23);

        return baos.toByteArray();

    }
}
